<?php
/**
 * Thumbnailer class.
 *
 * @author Lei Lee
 * @version 1.0
 */
class Thumbnail {
	/**
	 * Create a thumbnail.
	 *
	 * @param string $source
	 * @param int $width
	 * @param int $height
	 * @param string $dest
	 */
	public function create($source, $width, $height, $dest = NULL) {
		if (!extension_loaded('gd'))
			throw new GD2NotInstalledException('Detects that the server has not been installed GD library to create thumbnails can not be completed.');
		
		if (!function_exists('imagegd2'))
			throw new GD2NotInstalledException('GD library version must be 2.0 or above.');
		
		if (!is_file($source))
			throw new FileNotFoundException('File does not exist.');
			
		// Get the image width and height ...
		list($thumb_src, $src_w, $src_h) = $this->getResource($source);
		
		if ($thumb_src == NULL)
			throw new CreateImageException('Failure to obtain an image resource.', -1);
			
		// Thumbnail location information calculation ...
		if ($height < ( int ) (($src_h * $width) / $src_w)) {
			$x = $src_w;
			$y = ( int ) (($src_w * $height) / $width);
		} else {
			$x = ( int ) (($src_h * $width) / $height);
			$y = $src_h;
		}
		
		if ($thumb_src) {
			$thumb_dst = imagecreatetruecolor($width, $height);
			
			imagecopyresampled($thumb_dst, $thumb_src, 0, 0, 0, 0, $width, $height, $x, $y);
			
			// If you set $dest parameter, then automatically save the image to physical disk ...
			if (!is_null($dest)) {
				if (is_file($dest))
					unlink($dest);
				imagejpeg($thumb_dst, $dest, 100);
			} else {
				header('Content-type: image/jpeg');
				imagejpeg($thumb_dst, NULL, 100);
			}
			
			imagedestroy($thumb_src);
			imagedestroy($thumb_dst);
		}
	}
	
	/**
	 * Create the same proportion of the thumbnail.
	 *
	 * @param string $source
	 * @param string $dest
	 * @param int $wh
	 * @param boolean $is_width
	 * @param int $quality
	 */
	function scaling($source, $dest, $wh = 1024, $is_width = true, $quality = 100) {
		if (!extension_loaded('gd'))
			throw new GD2NotInstalledException('Detects that the server has not been installed GD library to create thumbnails can not be completed.');
		
		if (!function_exists('imagegd2'))
			throw new GD2NotInstalledException('GD library version must be 2.0 or above.');
		
		if (!is_file($source))
			throw new FileNotFoundException('File does not exist.');
			
		// Get the image width and height ...
		list($thumb_src, $src_w, $src_h) = $this->getResource($source);
		
		if ($thumb_src == NULL)
			throw new CreateImageException('Failure to obtain an image resource.', -1);
		
		if ($is_width) {
			if ($src_w <= $wh) {
				return false;
			} else {
				$width = $wh;
				$height = ( int ) (( float ) $src_h * $wh / $src_w);
			}
		} else {
			if ($src_h <= $wh) {
				return false;
			} else {
				$width = ( int ) (( float ) $src_w * $wh / $src_h);
				$height = $wh;
			}
		}
		
		try {
			if ($thumb_src) {
				$thumb_dst = imagecreatetruecolor($width, $height);
				
				imagecopyresampled($thumb_dst, $thumb_src, 0, 0, 0, 0, $width, $height, $src_w, $src_h);
				
				if (is_file($dest)) {
					unlink($dest);
				}
				imagejpeg($thumb_dst, $dest, $quality);
				
				imagedestroy($thumb_src);
				imagedestroy($thumb_dst);
			}
		} catch (Exception $ex) {
			throw new CreateImageException('Scaling image failed.(' . $ex->getMessage() . ')', -1);
		}
		
		return true;
	}
	
	/**
	 * Generate image watermark.
	 *
	 * @param string $src
	 * @param string $watermark
	 * @param string $position
	 * @param int $quality
	 * @return boolean
	 */
	function watermark($source, $watermark, $position = 'rb', $quality = 100) {
		if (!extension_loaded('gd'))
			throw new GD2NotInstalledException('Detects that the server has not been installed GD library to create thumbnails can not be completed.');
		
		if (!function_exists('imagegd2'))
			throw new GD2NotInstalledException('GD library version must be 2.0 or above.');
		
		if (!is_file($source))
			throw new FileNotFoundException('File does not exist.(' . $source . ')');
		if (!is_file($watermark))
			throw new FileNotFoundException('File does not exist.(' . $watermark . ')');
		
		try {
			list($image_src, $im_w1, $im_h1) = $this->getResource($source);
			list($image_wtm, $im_w2, $im_h2) = $this->getResource($watermark);
			
			if ($image_src && $image_wtm) {
				$dst_x = $im_w1 - $im_w2;
				$dst_y = $im_h1 - $im_h2;
				
				switch ($position) {
					case 'lt' :
						$dst_x = 0;
						$dst_y = 0;
						break;
					case 'rt' :
						$dst_x = $im_w1 - $im_w2;
						$dst_y = 0;
						break;
					case 'lb' :
						$dst_x = 0;
						$dst_y = $im_h1 - $im_h2;
						break;
					case 'rb' :
						$dst_x = $im_w1 - $im_w2;
						$dst_y = $im_h1 - $im_h2;
						break;
					case 'mt' :
						$dst_x = ( int ) (($im_w1 - $im_w2) / 2);
						$dst_y = 0;
						break;
					case 'mb' :
						$dst_x = ( int ) (($im_w1 - $im_w2) / 2);
						$dst_y = $im_h1 - $im_h2;
						break;
					case 'center' :
						$dst_x = ( int ) (($im_w1 - $im_w2) / 2);
						$dst_y = ( int ) (($im_h1 - $im_h2) / 2);
						break;
				}
				
				imagecopy($image_src, $image_wtm, $dst_x, $dst_y, 0, 0, $im_w2, $im_h2);
				
				if (is_file($source))
					unlink($source);
				imagejpeg($image_src, $source, $quality);
				
				imagedestroy($image_src);
				imagedestroy($image_wtm);
			}
		} catch (Exception $ex) {
			throw new CreateImageException('Watermark image into failure.(' . $ex->getMessage() . ')', -1);
		}
		
		return true;
	}
	
	/**
	 * Resources to get the image object.
	 *
	 * @param string $source
	 * @return array
	 */
	private function getResource($source) {
		list($w, $h, $type) = getimagesize($source);
		
		switch ($type) {
			case IMAGETYPE_JPEG :
			case IMAGETYPE_JPEG2000 :
				return array(imagecreatefromjpeg($source), $w, $h);
			case IMAGETYPE_GIF :
				return array(imagecreatefromgif($source), $w, $h);
			case IMAGETYPE_PNG :
				return array(imagecreatefrompng($source), $w, $h);
			default :
				return false;
		}
	}
}